package com.android.settings.audio.peq.peq.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import androidx.annotation.Nullable;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Created by We on 2023/3/17
 */
public class ChartView extends View {
    private Paint paint;
    private Path path;
    private Shader lineShader;
    private Shader areaShader;
    private List<PointF> bezierPoints;

    public ChartView(Context context) {
        super(context);
        init();
    }

    public ChartView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public ChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    public ChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }

    private void init() {
        this.path = new Path();
        this.paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        this.bezierPoints = new ArrayList<>();
        PointF[] points = buildKnots(xValues, yValues);
        this.bezierPoints.addAll(Arrays.asList(points));
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        drawGrid(canvas);
        drawPath(canvas);
    }

    private void drawGrid(Canvas canvas) {
        paint.setARGB(100, 200, 200, 200);
        paint.setStrokeWidth(3);
        paint.setStyle(Paint.Style.STROKE);

        //水平刻度线
        int offsetY = 1;

        final int gridColumnCount = 11;
        final int gridRowCount = 12;
        final int gridSize = Math.min(getHeight(), getWidth()) / gridRowCount;

        for (int i = 0; i < gridRowCount + 1; ++i) {
            canvas.drawLine(0, offsetY + i * gridSize, getWidth(), offsetY + i * gridSize, paint);
        }
        //垂直刻度线
        int offsetX = 1;
        for (int i = 0; i < gridColumnCount + 1; ++i) {
            canvas.drawLine(offsetX + i * gridSize, 0, offsetX + i * gridSize, getHeight(), paint);
        }
    }

    private void drawPath(Canvas canvas) {
        boolean 使用点集 = true;
        if (使用点集) {
            List<PointF> points = bezierPoints;//Dataset.buildBezierPoints(bezierPoints);
            path.reset();
            PointF startPoint = points.get(0);
            path.moveTo(startPoint.x, startPoint.y);
            paint.setColor(Color.BLUE);
            this.paint.setStrokeWidth(4);
            this.paint.setStyle(Paint.Style.STROKE);
            for (PointF point : points) {
                path.lineTo(point.x, point.y);
                canvas.drawPath(path, paint);
            }
        } else {
            path.reset();
            PointF startPoint = bezierPoints.get(0);
            path.moveTo(startPoint.x, startPoint.y);//起始点
            paint.setColor(Color.RED);
            this.paint.setStrokeWidth(5);
            this.paint.setStyle(Paint.Style.STROKE);
            //三阶
            path.cubicTo(/*控制点1*/bezierPoints.get(1).x, bezierPoints.get(1).y, /*控制点2*/bezierPoints.get(2).x, bezierPoints.get(2).y, /*结束点*/bezierPoints.get(3).x, bezierPoints.get(3).y);
            canvas.drawPath(path, paint);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return super.onTouchEvent(event);
    }

    private double[] xValues, yValues;
    private double preAmp;

    public void updateData(double[] xValues, double[] yValues, double preAmp) {
        this.xValues = xValues;
        this.yValues = yValues;
        this.preAmp = preAmp;

        if (getWidth() > 0 && getHeight() > 0)/*onMeasure*/ {
            this.bezierPoints = new ArrayList<>();
            PointF[] points = buildKnots(xValues, yValues);
            this.bezierPoints.addAll(Arrays.asList(points));
            invalidate();
        }
    }

    /**
     * 对给定的数值点，生成对应点的坐标
     * </ul>
     *
     * @param xValues
     * @param yValues
     * @return
     */
    private PointF[] buildKnots(double[] xValues, double[] yValues) {
        if (xValues == null) {
            return null;
        }

        final int LEN = xValues.length;
        if (LEN < 1) {
            return null;
        }

        // 计算数值点坐标
        PointF[] knots = new PointF[LEN];
        final float xOffset = 0;
        final float yOffset = getWidth() / 2f;

        int left = 0;
        int right = getWidth();
        int top = 0;
        int bottom = 0;//getHeight()
        double minX = 0, maxX = 0;
        double minY = 0, maxY = 0;
        for (double xValue : xValues) {
            if (xValue > maxX) {
                maxX = xValue;
            }
        }
        for (double yValue : yValues) {
            if (yValue > maxX) {
                maxY = yValue;
            }
        }

        final double xPixelsPerUnit = 324.14;//(right - left) / (maxX - minX);
        final double yPixelsPerUnit = 47.54;//((bottom - top) / (maxY - minY));

        for (int i = 0; i < LEN; i++) {
            knots[i] = new PointF((float) (left + xPixelsPerUnit * (xValues[i] - minX) + xOffset), (float) (bottom - yPixelsPerUnit * (yValues[i] - minY) + yOffset - this.preAmp * yPixelsPerUnit));
        }

        return knots;
    }
}
